package com.cutefool.zero.code.admin.dbms.service;

import com.cutefool.core.exec.BizException;
import com.cutefool.core.kits.bean.Beans;
import com.cutefool.core.kits.consts.Status;
import com.cutefool.core.res.ResponseCode;
import com.cutefool.dsl.mybatis.core.dsl.builder.InsertDsl;
import com.cutefool.dsl.mybatis.core.dsl.builder.QueryDsl;
import com.cutefool.dsl.mybatis.core.dsl.builder.UpdateDsl;
import com.cutefool.dsl.mybatis.core.dsl.operation.CuteCurdOperation;
import com.cutefool.rds.enums.RdsDbType;
import com.cutefool.rds.meta.libs.ColumnLibs;
import com.cutefool.rds.template.RdsTemplate;
import com.cutefool.zero.code.admin.consts.Constants;
import com.cutefool.zero.code.admin.dbms.dto.DbDTO;
import com.cutefool.zero.code.admin.dbms.dto.DbmsDTO;
import com.cutefool.zero.code.admin.dbms.support.DbmsMetas;
import com.cutefool.zero.code.admin.meta.model.context.RdsTemplateContext;
import com.cutefool.zero.code.core.domain.Db;
import com.cutefool.zero.code.core.domain.Dbms;
import com.zaxxer.hikari.HikariDataSource;
import jakarta.annotation.Resource;
import org.mybatis.dynamic.sql.SqlBuilder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.Collection;
import java.util.List;
import java.util.Objects;
import java.util.Optional;

@Service
@SuppressWarnings({"unchecked", "rawtypes"})
public class DbmsService {

    @Resource
    private CuteCurdOperation cuteCurdOperation;

    @Resource
    private RdsTemplateContext rdsTemplateContext;

    @Transactional(rollbackFor = RuntimeException.class)
    public Long create(DbmsDTO dto) {
        // 检测数据配置是否可用
        this.doDbCheck(dto.getDbs());
        // 存储数据源配置
        InsertDsl<Dbms> insertDbmsDsl = InsertDsl.newInstance(Dbms.instance()).entity(dto);
        this.cuteCurdOperation.create(insertDbmsDsl);
        Dbms entity = insertDbmsDsl.getEntity();
        InsertDsl<Db> insertDbDsl = this.dbInsert(entity, dto.getDbs());
        this.cuteCurdOperation.create(insertDbDsl);
        // 处理各个数据库的函数
        Collection<Db> entities = insertDbDsl.getEntities();
        entities.stream()
                .filter(e -> Status.isTrue(e.getWritable()))
                .forEach(e -> RdsDbType.byName(e.getType())
                        .ifPresent(s -> {
                            RdsTemplate rdsTemplate = rdsTemplateContext.get(e);
                            s.getFunctioned().drop(rdsTemplate.getJdbcTemplate());
                            s.getFunctioned().doExecute((HikariDataSource) rdsTemplate.getJdbcTemplate().getDataSource());
                        }));
        return insertDbmsDsl.getEntity().getId();
    }

    @Transactional(rollbackFor = RuntimeException.class)
    public void update(DbmsDTO dto) {
        // 存储数据源配置
        UpdateDsl<Dbms> updateDbmsDsl = UpdateDsl.newInstance(Dbms.instance()).entity(dto);
        this.cuteCurdOperation.update(updateDbmsDsl);
        // 存储数据源关联数据库配置
        UpdateDsl<Db> updateDbDsl = UpdateDsl.newInstance(Db.instance()).entity(dto.getDbs());
        this.cuteCurdOperation.update(updateDbDsl);
    }

    public Db getDevDb(Long id) {
        QueryDsl<Db> queryDsl = QueryDsl.newInstance(Db.instance(), where -> {
            where.and(Db.instance().table().dbmsId, SqlBuilder.isEqualTo(id));
            where.and(Db.instance().table().env, SqlBuilder.isEqualTo(Constants.ENV_DEV));
            where.and(Db.instance().table().writable, SqlBuilder.isEqualTo(Status.STATUS_TRUE));
        });
        Optional<Db> optional = this.cuteCurdOperation.get(queryDsl);
        return optional.orElseThrow(() -> new BizException(ResponseCode.API_ERROR.getCode(), "未配置数据库配置"));
    }

    public List<String> listTables(Long id) {
        Db db = this.getDevDb(id);
        return DbmsMetas.tables(db);
    }


    public List<ColumnLibs> listColumn(Long id, String table) {
        Db db = this.getDevDb(id);
        return DbmsMetas.columns(db, table);
    }

    private InsertDsl<Db> dbInsert(Dbms entity, List<DbDTO> dbs) {
        DbDTO devDB = dbs.stream()
                .filter(e -> Objects.equals(e.getEnv(), Constants.ENV_DEV))
                .findAny()
                .orElseThrow(BizException::new);
        // 存储数据源关联数据库配置
        return InsertDsl.newInstance(Db.instance()).entities(dbs, (d, s) -> {
            // 如果是复用开发环境配置
            if (Status.isTrue(s.getMultiplex())) {
                // 拷贝开发环境属性到目标对象
                Beans.processObject(d, devDB);
                // 放置拷贝错误
                d.setMultiplex(s.getMultiplex());
                d.setEnv(s.getEnv());
                d.setName(s.getName());
            }
            d.setDbmsId(entity.getId());
            d.setCompanyId(entity.getCompanyId());
            d.setAppId(entity.getAppId());
            // 目前没有设计分库
            d.setWritable(Status.STATUS_TRUE);
        });
    }

    private void doDbCheck(List<DbDTO> dbs) {
        // 只检测不是复用配置的db
        for (DbDTO db : dbs) {
            DbmsMetas.test(db);
        }
    }

}

